﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace ForceSystem.Untangler
{
    /// <summary>
    /// This class helps load assembly that resolves assembly references.
    /// </summary>
    internal class AssemblyLoader
    {
        List<string> _searchPathes;

        public AssemblyLoader()
        {
            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve +=
                CurrentDomainReflectionOnlyAssemblyResolve;

            AppDomain.CurrentDomain.AssemblyResolve +=
                CurrentDomainAssemblyResolve;

        }

        ~AssemblyLoader()
        {
            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -=
                CurrentDomainReflectionOnlyAssemblyResolve;

            AppDomain.CurrentDomain.AssemblyResolve -=
                CurrentDomainAssemblyResolve;
        }

        public Assembly ReflectionOnlyLoad(string filename)
        {
            return Load(filename, true);
        }

        public Assembly Load(string filename)
        {
            return Load(filename, false);
        }

        public Assembly Load(string filename, bool reflectionOnly)
        {
            _searchPathes = new List<string> {Path.GetDirectoryName(Path.GetFullPath(filename))};
            return reflectionOnly ? Assembly.ReflectionOnlyLoadFrom(filename) : Assembly.LoadFrom(filename);
        }

        string FindFile(string assemblyName)
        {
            return _searchPathes.Select(searchPath => Path.Combine(searchPath, assemblyName + ".dll")).FirstOrDefault(File.Exists);
        }

        Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
        {
            string path = FindFile(args.Name.Split(",".ToCharArray())[0]);
            return String.IsNullOrEmpty(path) ? null : Assembly.LoadFile(path);
        }

        Assembly CurrentDomainReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
        {
            string path = FindFile(args.Name.Split(",".ToCharArray())[0]);

            Assembly result = null;
            try
            {
                result = !String.IsNullOrEmpty(path) ? Assembly.ReflectionOnlyLoadFrom(path) : Assembly.ReflectionOnlyLoad(args.Name);
            }
// ReSharper disable EmptyGeneralCatchClause
            catch (Exception)
// ReSharper restore EmptyGeneralCatchClause
            {
            }

            return result;
        }

    }
}
